home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / lib / tk2.3 / dist / tkRectOval.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-08-24  |  26.0 KB  |  879 lines

  1. /* 
  2.  * tkRectOval.c --
  3.  *
  4.  *    This file implements rectangle and oval items for canvas
  5.  *    widgets.
  6.  *
  7.  * Copyright 1991-1992 Regents of the University of California.
  8.  * Permission to use, copy, modify, and distribute this
  9.  * software and its documentation for any purpose and without
  10.  * fee is hereby granted, provided that the above copyright
  11.  * notice appear in all copies.  The University of California
  12.  * makes no representations about the suitability of this
  13.  * software for any purpose.  It is provided "as is" without
  14.  * express or implied warranty.
  15.  */
  16.  
  17. #ifndef lint
  18. static char rcsid[] = "$Header: /user6/ouster/wish/RCS/tkRectOval.c,v 1.15 92/08/24 09:23:58 ouster Exp $ SPRITE (Berkeley)";
  19. #endif
  20.  
  21. #include <stdio.h>
  22. #include <math.h>
  23. #include "tkConfig.h"
  24. #include "tkInt.h"
  25. #include "tkCanvas.h"
  26.  
  27. /*
  28.  * The structure below defines the record for each rectangle/oval item.
  29.  */
  30.  
  31. typedef struct RectOvalItem  {
  32.     Tk_Item header;        /* Generic stuff that's the same for all
  33.                  * types.  MUST BE FIRST IN STRUCTURE. */
  34.     double bbox[4];        /* Coordinates of bounding box for rectangle
  35.                  * or oval (x1, y1, x2, y2).  Item includes
  36.                  * x1 and x2 but not y1 and y2. */
  37.     int width;            /* Width of outline. */
  38.     XColor *outlineColor;    /* Color for outline. */
  39.     XColor *fillColor;        /* Color for filling rectangle/oval. */
  40.     Pixmap fillStipple;        /* Stipple bitmap for filling item. */
  41.     GC outlineGC;        /* Graphics context for outline. */
  42.     GC fillGC;            /* Graphics context for filling item. */
  43. } RectOvalItem;
  44.  
  45. /*
  46.  * Information used for parsing configuration specs:
  47.  */
  48.  
  49. static Tk_ConfigSpec configSpecs[] = {
  50.     {TK_CONFIG_COLOR, "-fill", (char *) NULL, (char *) NULL,
  51.     (char *) NULL, Tk_Offset(RectOvalItem, fillColor), TK_CONFIG_NULL_OK},
  52.     {TK_CONFIG_COLOR, "-outline", (char *) NULL, (char *) NULL,
  53.     "black", Tk_Offset(RectOvalItem, outlineColor), TK_CONFIG_NULL_OK},
  54.     {TK_CONFIG_BITMAP, "-stipple", (char *) NULL, (char *) NULL,
  55.     (char *) NULL, Tk_Offset(RectOvalItem, fillStipple), TK_CONFIG_NULL_OK},
  56.     {TK_CONFIG_CUSTOM, "-tags", (char *) NULL, (char *) NULL,
  57.     (char *) NULL, 0, TK_CONFIG_NULL_OK, &tkCanvasTagsOption},
  58.     {TK_CONFIG_PIXELS, "-width", (char *) NULL, (char *) NULL,
  59.     "1", Tk_Offset(RectOvalItem, width), TK_CONFIG_DONT_SET_DEFAULT},
  60.     {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL,
  61.     (char *) NULL, 0, 0}
  62. };
  63.  
  64. /*
  65.  * Prototypes for procedures defined in this file:
  66.  */
  67.  
  68. static void        ComputeRectOvalBbox _ANSI_ARGS_((Tk_Canvas *canvasPtr,
  69.                 RectOvalItem *rectOvalPtr));
  70. static int        ConfigureRectOval _ANSI_ARGS_((
  71.                 Tk_Canvas *canvasPtr, Tk_Item *itemPtr, int argc,
  72.                 char **argv, int flags));
  73. static int        CreateRectOval _ANSI_ARGS_((Tk_Canvas *canvasPtr,
  74.                 struct Tk_Item *itemPtr, int argc, char **argv));
  75. static void        DeleteRectOval _ANSI_ARGS_((Tk_Item *itemPtr));
  76. static void        DisplayRectOval _ANSI_ARGS_((Tk_Canvas *canvasPtr,
  77.                 Tk_Item *itemPtr, Drawable dst));
  78. static int        OvalToArea _ANSI_ARGS_((Tk_Canvas *canvasPtr,
  79.                 Tk_Item *itemPtr, double *areaPtr));
  80. static double        OvalToPoint _ANSI_ARGS_((Tk_Canvas *canvasPtr,
  81.                 Tk_Item *itemPtr, double *pointPtr));
  82. static int        RectOvalCoords _ANSI_ARGS_((Tk_Canvas *canvasPtr,
  83.                 Tk_Item *itemPtr, int argc, char **argv));
  84. static int        RectToArea _ANSI_ARGS_((Tk_Canvas *canvasPtr,
  85.                 Tk_Item *itemPtr, double *areaPtr));
  86. static double        RectToPoint _ANSI_ARGS_((Tk_Canvas *canvasPtr,
  87.                 Tk_Item *itemPtr, double *pointPtr));
  88. static void        ScaleRectOval _ANSI_ARGS_((Tk_Canvas *canvasPtr,
  89.                 Tk_Item *itemPtr, double originX, double originY,
  90.                 double scaleX, double scaleY));
  91. static void        TranslateRectOval _ANSI_ARGS_((Tk_Canvas *canvasPtr,
  92.                 Tk_Item *itemPtr, double deltaX, double deltaY));
  93.  
  94. /*
  95.  * The structures below defines the rectangle and oval item types
  96.  * by means of procedures that can be invoked by generic item code.
  97.  */
  98.  
  99. Tk_ItemType TkRectangleType = {
  100.     "rectangle",            /* name */
  101.     sizeof(RectOvalItem),        /* itemSize */
  102.     CreateRectOval,            /* createProc */
  103.     configSpecs,            /* configSpecs */
  104.     ConfigureRectOval,            /* configureProc */
  105.     RectOvalCoords,            /* coordProc */
  106.     DeleteRectOval,            /* deleteProc */
  107.     DisplayRectOval,            /* displayProc */
  108.     0,                    /* alwaysRedraw */
  109.     RectToPoint,            /* pointProc */
  110.     RectToArea,                /* areaProc */
  111.     (Tk_ItemPostscriptProc *) NULL,    /* postscriptProc */
  112.     ScaleRectOval,            /* scaleProc */
  113.     TranslateRectOval,            /* translateProc */
  114.     (Tk_ItemIndexProc *) NULL,        /* indexProc */
  115.     (Tk_ItemCursorProc *) NULL,        /* cursorProc */
  116.     (Tk_ItemSelectionProc *) NULL,    /* selectionProc */
  117.     (Tk_ItemInsertProc *) NULL,        /* insertProc */
  118.     (Tk_ItemDCharsProc *) NULL,        /* dTextProc */
  119.     (Tk_ItemType *) NULL        /* nextPtr */
  120. };
  121.  
  122. Tk_ItemType TkOvalType = {
  123.     "oval",                /* name */
  124.     sizeof(RectOvalItem),        /* itemSize */
  125.     CreateRectOval,            /* createProc */
  126.     configSpecs,            /* configSpecs */
  127.     ConfigureRectOval,            /* configureProc */
  128.     RectOvalCoords,            /* coordProc */
  129.     DeleteRectOval,            /* deleteProc */
  130.     DisplayRectOval,            /* displayProc */
  131.     0,                    /* alwaysRedraw */
  132.     OvalToPoint,            /* pointProc */
  133.     OvalToArea,                /* areaProc */
  134.     (Tk_ItemPostscriptProc *) NULL,    /* postscriptProc */
  135.     ScaleRectOval,            /* scaleProc */
  136.     TranslateRectOval,            /* translateProc */
  137.     (Tk_ItemIndexProc *) NULL,        /* indexProc */
  138.     (Tk_ItemCursorProc *) NULL,        /* cursorProc */
  139.     (Tk_ItemSelectionProc *) NULL,    /* selectionProc */
  140.     (Tk_ItemInsertProc *) NULL,        /* insertProc */
  141.     (Tk_ItemDCharsProc *) NULL,        /* dTextProc */
  142.     (Tk_ItemType *) NULL        /* nextPtr */
  143. };
  144.  
  145. /*
  146.  *--------------------------------------------------------------
  147.  *
  148.  * CreateRectOval --
  149.  *
  150.  *    This procedure is invoked to create a new rectangle
  151.  *    or oval item in a canvas.
  152.  *
  153.  * Results:
  154.  *    A standard Tcl return value.  If an error occurred in
  155.  *    creating the item, then an error message is left in
  156.  *    canvasPtr->interp->result;  in this case itemPtr is
  157.  *    left uninitialized, so it can be safely freed by the
  158.  *    caller.
  159.  *
  160.  * Side effects:
  161.  *    A new rectangle or oval item is created.
  162.  *
  163.  *--------------------------------------------------------------
  164.  */
  165.  
  166. static int
  167. CreateRectOval(canvasPtr, itemPtr, argc, argv)
  168.     register Tk_Canvas *canvasPtr;    /* Canvas to hold new item. */
  169.     Tk_Item *itemPtr;            /* Record to hold new item;  header
  170.                      * has been initialized by caller. */
  171.     int argc;                /* Number of arguments in argv. */
  172.     char **argv;            /* Arguments describing rectangle. */
  173. {
  174.     register RectOvalItem *rectOvalPtr = (RectOvalItem *) itemPtr;
  175.  
  176.     if (argc < 4) {
  177.     Tcl_AppendResult(canvasPtr->interp, "wrong # args:  should be \"",
  178.         Tk_PathName(canvasPtr->tkwin), "\" create ",
  179.         itemPtr->typePtr->name, " x1 y1 x2 y2 ?options?",
  180.         (char *) NULL);
  181.     return TCL_ERROR;
  182.     }
  183.  
  184.     /*
  185.      * Carry out initialization that is needed in order to clean
  186.      * up after errors during the the remainder of this procedure.
  187.      */
  188.  
  189.     rectOvalPtr->width = 1;
  190.     rectOvalPtr->outlineColor = NULL;
  191.     rectOvalPtr->fillColor = NULL;
  192.     rectOvalPtr->fillStipple = None;
  193.     rectOvalPtr->outlineGC = None;
  194.     rectOvalPtr->fillGC = None;
  195.  
  196.     /*
  197.      * Process the arguments to fill in the item record.
  198.      */
  199.  
  200.     if ((TkGetCanvasCoord(canvasPtr, argv[0], &rectOvalPtr->bbox[0]) != TCL_OK)
  201.         || (TkGetCanvasCoord(canvasPtr, argv[1],
  202.         &rectOvalPtr->bbox[1]) != TCL_OK)
  203.         || (TkGetCanvasCoord(canvasPtr, argv[2],
  204.             &rectOvalPtr->bbox[2]) != TCL_OK)
  205.         || (TkGetCanvasCoord(canvasPtr, argv[3],
  206.             &rectOvalPtr->bbox[3]) != TCL_OK)) {
  207.     return TCL_ERROR;
  208.     }
  209.  
  210.     if (ConfigureRectOval(canvasPtr, itemPtr, argc-4, argv+4, 0) != TCL_OK) {
  211.     DeleteRectOval(itemPtr);
  212.     return TCL_ERROR;
  213.     }
  214.     return TCL_OK;
  215. }
  216.  
  217. /*
  218.  *--------------------------------------------------------------
  219.  *
  220.  * RectOvalCoords --
  221.  *
  222.  *    This procedure is invoked to process the "coords" widget
  223.  *    command on rectangles and ovals.  See the user documentation
  224.  *    for details on what it does.
  225.  *
  226.  * Results:
  227.  *    Returns TCL_OK or TCL_ERROR, and sets canvasPtr->interp->result.
  228.  *
  229.  * Side effects:
  230.  *    The coordinates for the given item may be changed.
  231.  *
  232.  *--------------------------------------------------------------
  233.  */
  234.  
  235. static int
  236. RectOvalCoords(canvasPtr, itemPtr, argc, argv)
  237.     register Tk_Canvas *canvasPtr;    /* Canvas containing item. */
  238.     Tk_Item *itemPtr;            /* Item whose coordinates are to be
  239.                      * read or modified. */
  240.     int argc;                /* Number of coordinates supplied in
  241.                      * argv. */
  242.     char **argv;            /* Array of coordinates: x1, y1,
  243.                      * x2, y2, ... */
  244. {
  245.     register RectOvalItem *rectOvalPtr = (RectOvalItem *) itemPtr;
  246.     char buffer[500];
  247.  
  248.     if (argc == 0) {
  249.     sprintf(buffer, "%g %g %g %g", rectOvalPtr->bbox[0],
  250.         rectOvalPtr->bbox[1], rectOvalPtr->bbox[2],
  251.         rectOvalPtr->bbox[3]);
  252.     Tcl_SetResult(canvasPtr->interp, buffer, TCL_VOLATILE);
  253.     } else if (argc == 4) {
  254.     if ((TkGetCanvasCoord(canvasPtr, argv[0],
  255.             &rectOvalPtr->bbox[0]) != TCL_OK)
  256.         || (TkGetCanvasCoord(canvasPtr, argv[1],
  257.             &rectOvalPtr->bbox[1]) != TCL_OK)
  258.         || (TkGetCanvasCoord(canvasPtr, argv[2],
  259.             &rectOvalPtr->bbox[2]) != TCL_OK)
  260.         || (TkGetCanvasCoord(canvasPtr, argv[3],
  261.             &rectOvalPtr->bbox[3]) != TCL_OK)) {
  262.         return TCL_ERROR;
  263.     }
  264.     ComputeRectOvalBbox(canvasPtr, rectOvalPtr);
  265.     } else {
  266.     sprintf(canvasPtr->interp->result,
  267.         "wrong # coordinates:  expected 0 or 4, got %d",
  268.         argc);
  269.     return TCL_ERROR;
  270.     }
  271.     return TCL_OK;
  272. }
  273.  
  274. /*
  275.  *--------------------------------------------------------------
  276.  *
  277.  * ConfigureRectOval --
  278.  *
  279.  *    This procedure is invoked to configure various aspects
  280.  *    of a rectangle or oval item, such as its border and
  281.  *    background colors.
  282.  *
  283.  * Results:
  284.  *    A standard Tcl result code.  If an error occurs, then
  285.  *    an error message is left in canvasPtr->interp->result.
  286.  *
  287.  * Side effects:
  288.  *    Configuration information, such as colors and stipple
  289.  *    patterns, may be set for itemPtr.
  290.  *
  291.  *--------------------------------------------------------------
  292.  */
  293.  
  294. static int
  295. ConfigureRectOval(canvasPtr, itemPtr, argc, argv, flags)
  296.     Tk_Canvas *canvasPtr;    /* Canvas containing itemPtr. */
  297.     Tk_Item *itemPtr;        /* Rectangle item to reconfigure. */
  298.     int argc;            /* Number of elements in argv.  */
  299.     char **argv;        /* Arguments describing things to configure. */
  300.     int flags;            /* Flags to pass to Tk_ConfigureWidget. */
  301. {
  302.     register RectOvalItem *rectOvalPtr = (RectOvalItem *) itemPtr;
  303.     XGCValues gcValues;
  304.     GC newGC;
  305.     unsigned long mask;
  306.  
  307.     if (Tk_ConfigureWidget(canvasPtr->interp, canvasPtr->tkwin,
  308.         configSpecs, argc, argv, (char *) rectOvalPtr, flags) != TCL_OK) {
  309.     return TCL_ERROR;
  310.     }
  311.  
  312.     /*
  313.      * A few of the options require additional processing, such as
  314.      * graphics contexts.
  315.      */
  316.  
  317.     if (rectOvalPtr->outlineColor == NULL) {
  318.     newGC = None;
  319.     } else {
  320.     gcValues.foreground = rectOvalPtr->outlineColor->pixel;
  321.     gcValues.cap_style = CapProjecting;
  322.     if (rectOvalPtr->width < 0) {
  323.         rectOvalPtr->width = 1;
  324.     }
  325.     gcValues.line_width = rectOvalPtr->width;
  326.     mask = GCForeground|GCCapStyle|GCLineWidth;
  327.     newGC = Tk_GetGC(canvasPtr->tkwin, mask, &gcValues);
  328.     }
  329.     if (rectOvalPtr->outlineGC != None) {
  330.     Tk_FreeGC(rectOvalPtr->outlineGC);
  331.     }
  332.     rectOvalPtr->outlineGC = newGC;
  333.  
  334.     if (rectOvalPtr->fillColor == NULL) {
  335.     newGC = None;
  336.     } else {
  337.     gcValues.foreground = rectOvalPtr->fillColor->pixel;
  338.     if (rectOvalPtr->fillStipple != None) {
  339.         gcValues.stipple = rectOvalPtr->fillStipple;
  340.         gcValues.fill_style = FillStippled;
  341.         mask = GCForeground|GCStipple|GCFillStyle;
  342.     } else {
  343.         mask = GCForeground;
  344.     }
  345.     newGC = Tk_GetGC(canvasPtr->tkwin, mask, &gcValues);
  346.     }
  347.     if (rectOvalPtr->fillGC != None) {
  348.     Tk_FreeGC(rectOvalPtr->fillGC);
  349.     }
  350.     rectOvalPtr->fillGC = newGC;
  351.     ComputeRectOvalBbox(canvasPtr, rectOvalPtr);
  352.  
  353.     return TCL_OK;
  354. }
  355.  
  356. /*
  357.  *--------------------------------------------------------------
  358.  *
  359.  * DeleteRectOval --
  360.  *
  361.  *    This procedure is called to clean up the data structure
  362.  *    associated with a rectangle or oval item.
  363.  *
  364.  * Results:
  365.  *    None.
  366.  *
  367.  * Side effects:
  368.  *    Resources associated with itemPtr are released.
  369.  *
  370.  *--------------------------------------------------------------
  371.  */
  372.  
  373. static void
  374. DeleteRectOval(itemPtr)
  375.     Tk_Item *itemPtr;            /* Item that is being deleted. */
  376. {
  377.     register RectOvalItem *rectOvalPtr = (RectOvalItem *) itemPtr;
  378.  
  379.     if (rectOvalPtr->outlineColor != NULL) {
  380.     Tk_FreeColor(rectOvalPtr->outlineColor);
  381.     }
  382.     if (rectOvalPtr->fillColor != NULL) {
  383.     Tk_FreeColor(rectOvalPtr->fillColor);
  384.     }
  385.     if (rectOvalPtr->fillStipple != None) {
  386.     Tk_FreeBitmap(rectOvalPtr->fillStipple);
  387.     }
  388.     if (rectOvalPtr->outlineGC != None) {
  389.     Tk_FreeGC(rectOvalPtr->outlineGC);
  390.     }
  391.     if (rectOvalPtr->fillGC != None) {
  392.     Tk_FreeGC(rectOvalPtr->fillGC);
  393.     }
  394. }
  395.  
  396. /*
  397.  *--------------------------------------------------------------
  398.  *
  399.  * ComputeRectOvalBbox --
  400.  *
  401.  *    This procedure is invoked to compute the bounding box of
  402.  *    all the pixels that may be drawn as part of a rectangle
  403.  *    or oval.
  404.  *
  405.  * Results:
  406.  *    None.
  407.  *
  408.  * Side effects:
  409.  *    The fields x1, y1, x2, and y2 are updated in the header
  410.  *    for itemPtr.
  411.  *
  412.  *--------------------------------------------------------------
  413.  */
  414.  
  415.     /* ARGSUSED */
  416. static void
  417. ComputeRectOvalBbox(canvasPtr, rectOvalPtr)
  418.     Tk_Canvas *canvasPtr;        /* Canvas that contains item. */
  419.     register RectOvalItem *rectOvalPtr;    /* Item whose bbox is to be
  420.                      * recomputed. */
  421. {
  422.     int bloat;
  423.  
  424.     /*
  425.      * Make sure that the first coordinates are the lowest ones.
  426.      */
  427.  
  428.     if (rectOvalPtr->bbox[1] > rectOvalPtr->bbox[3]) {
  429.     double tmp;
  430.     tmp = rectOvalPtr->bbox[3];
  431.     rectOvalPtr->bbox[3] = rectOvalPtr->bbox[1];
  432.     rectOvalPtr->bbox[1] = tmp;
  433.     }
  434.     if (rectOvalPtr->bbox[0] > rectOvalPtr->bbox[2]) {
  435.     double tmp;
  436.     tmp = rectOvalPtr->bbox[2];
  437.     rectOvalPtr->bbox[2] = rectOvalPtr->bbox[0];
  438.     rectOvalPtr->bbox[0] = tmp;
  439.     }
  440.  
  441.     bloat = (rectOvalPtr->width+1)/2 + 1;
  442.     rectOvalPtr->header.x1 = rectOvalPtr->bbox[0] - bloat;
  443.     rectOvalPtr->header.y1 = rectOvalPtr->bbox[1] - bloat;
  444.     rectOvalPtr->header.x2 = rectOvalPtr->bbox[2] + bloat;
  445.     rectOvalPtr->header.y2 = rectOvalPtr->bbox[3] + bloat;
  446. }
  447.  
  448. /*
  449.  *--------------------------------------------------------------
  450.  *
  451.  * DisplayRectOval --
  452.  *
  453.  *    This procedure is invoked to draw a rectangle or oval
  454.  *    item in a given drawable.
  455.  *
  456.  * Results:
  457.  *    None.
  458.  *
  459.  * Side effects:
  460.  *    ItemPtr is drawn in drawable using the transformation
  461.  *    information in canvasPtr.
  462.  *
  463.  *--------------------------------------------------------------
  464.  */
  465.  
  466. static void
  467. DisplayRectOval(canvasPtr, itemPtr, drawable)
  468.     register Tk_Canvas *canvasPtr;    /* Canvas that contains item. */
  469.     Tk_Item *itemPtr;            /* Item to be displayed. */
  470.     Drawable drawable;            /* Pixmap or window in which to draw
  471.                      * item. */
  472. {
  473.     register RectOvalItem *rectOvalPtr = (RectOvalItem *) itemPtr;
  474.     Display *display = Tk_Display(canvasPtr->tkwin);
  475.     int x1, y1, x2, y2;
  476.  
  477.     /*
  478.      * Compute the screen coordinates of the bounding box for the item.
  479.      * Make sure that the bbox is at least one pixel large, since some
  480.      * X servers will die if it isn't.
  481.      */
  482.  
  483.     x1 = SCREEN_X(canvasPtr, rectOvalPtr->bbox[0]);
  484.     y1 = SCREEN_Y(canvasPtr, rectOvalPtr->bbox[1]);
  485.     x2 = SCREEN_X(canvasPtr, rectOvalPtr->bbox[2]);
  486.     y2 = SCREEN_Y(canvasPtr, rectOvalPtr->bbox[3]);
  487.     if (x2 <= x1) {
  488.     x2 = x1+1;
  489.     }
  490.     if (y2 <= y1) {
  491.     y2 = y1+1;
  492.     }
  493.  
  494.     /*
  495.      * Display filled box first (if wanted), then outline.
  496.      */
  497.  
  498.     if (rectOvalPtr->fillGC != None) {
  499.     if (rectOvalPtr->header.typePtr == &TkRectangleType) {
  500.         XFillRectangle(display, drawable, rectOvalPtr->fillGC,
  501.             x1, y1, (unsigned int) (x2-x1), (unsigned int) (y2-y1));
  502.     } else {
  503.         XFillArc(display, drawable, rectOvalPtr->fillGC,
  504.             x1, y1, (x2-x1), (y2-y1), 0, 360*64);
  505.     }
  506.     }
  507.     if (rectOvalPtr->outlineGC != None) {
  508.     if (rectOvalPtr->header.typePtr == &TkRectangleType) {
  509.         XDrawRectangle(display, drawable, rectOvalPtr->outlineGC,
  510.             x1, y1, (x2-x1-1), (y2-y1-1));
  511.     } else {
  512.         XDrawArc(display, drawable, rectOvalPtr->outlineGC,
  513.             x1, y1, (x2-x1-1), (y2-y1-1), 0, 360*64);
  514.     }
  515.     }
  516. }
  517.  
  518. /*
  519.  *--------------------------------------------------------------
  520.  *
  521.  * RectToPoint --
  522.  *
  523.  *    Computes the distance from a given point to a given
  524.  *    rectangle, in canvas units.
  525.  *
  526.  * Results:
  527.  *    The return value is 0 if the point whose x and y coordinates
  528.  *    are coordPtr[0] and coordPtr[1] is inside the rectangle.  If the
  529.  *    point isn't inside the rectangle then the return value is the
  530.  *    distance from the point to the rectangle.  If itemPtr is filled,
  531.  *    then anywhere in the interior is considered "inside"; if
  532.  *    itemPtr isn't filled, then "inside" means only the area
  533.  *    occupied by the outline.
  534.  *
  535.  * Side effects:
  536.  *    None.
  537.  *
  538.  *--------------------------------------------------------------
  539.  */
  540.  
  541.     /* ARGSUSED */
  542. static double
  543. RectToPoint(canvasPtr, itemPtr, pointPtr)
  544.     Tk_Canvas *canvasPtr;    /* Canvas containing item. */
  545.     Tk_Item *itemPtr;        /* Item to check against point. */
  546.     double *pointPtr;        /* Pointer to x and y coordinates. */
  547. {
  548.     register RectOvalItem *rectPtr = (RectOvalItem *) itemPtr;
  549.     double xDiff, yDiff, x1, y1, x2, y2, inc, tmp;
  550.  
  551.     /*
  552.      * Generate a new larger rectangle that includes the border
  553.      * width, if there is one.
  554.      */
  555.  
  556.     x1 = rectPtr->bbox[0];
  557.     y1 = rectPtr->bbox[1];
  558.     x2 = rectPtr->bbox[2];
  559.     y2 = rectPtr->bbox[3];
  560.     if (rectPtr->outlineGC != None) {
  561.     inc = rectPtr->width/2.0;
  562.     x1 -= inc;
  563.     y1 -= inc;
  564.     x2 += inc;
  565.     y2 += inc;
  566.     }
  567.  
  568.     /*
  569.      * If the point is inside the rectangle, handle specially:
  570.      * distance is 0 if rectangle is filled, otherwise compute
  571.      * distance to nearest edge of rectangle and subtract width
  572.      * of edge.
  573.      */
  574.  
  575.     if ((pointPtr[0] >= x1) && (pointPtr[0] < x2)
  576.         && (pointPtr[1] >= y1) && (pointPtr[1] < y2)) {
  577.     if ((rectPtr->fillGC != None) || (rectPtr->outlineGC == None)) {
  578.         return 0.0;
  579.     }
  580.     xDiff = pointPtr[0] - x1;
  581.     tmp = x2 - pointPtr[0];
  582.     if (tmp < xDiff) {
  583.         xDiff = tmp;
  584.     }
  585.     yDiff = pointPtr[1] - y1;
  586.     tmp = y2 - pointPtr[1];
  587.     if (tmp < yDiff) {
  588.         yDiff = tmp;
  589.     }
  590.     if (yDiff < xDiff) {
  591.         xDiff = yDiff;
  592.     }
  593.     xDiff -= rectPtr->width;
  594.     if (xDiff < 0.0) {
  595.         return 0.0;
  596.     }
  597.     return xDiff;
  598.     }
  599.  
  600.     /*
  601.      * Point is outside rectangle.
  602.      */
  603.  
  604.     if (pointPtr[0] < x1) {
  605.     xDiff = x1 - pointPtr[0];
  606.     } else if (pointPtr[0] > x2)  {
  607.     xDiff = pointPtr[0] - x2;
  608.     } else {
  609.     xDiff = 0;
  610.     }
  611.  
  612.     if (pointPtr[1] < y1) {
  613.     yDiff = y1 - pointPtr[1];
  614.     } else if (pointPtr[1] > y2)  {
  615.     yDiff = pointPtr[1] - y2;
  616.     } else {
  617.     yDiff = 0;
  618.     }
  619.  
  620.     return hypot(xDiff, yDiff);
  621. }
  622.  
  623. /*
  624.  *--------------------------------------------------------------
  625.  *
  626.  * OvalToPoint --
  627.  *
  628.  *    Computes the distance from a given point to a given
  629.  *    oval, in canvas units.
  630.  *
  631.  * Results:
  632.  *    The return value is 0 if the point whose x and y coordinates
  633.  *    are coordPtr[0] and coordPtr[1] is inside the oval.  If the
  634.  *    point isn't inside the oval then the return value is the
  635.  *    distance from the point to the oval.  If itemPtr is filled,
  636.  *    then anywhere in the interior is considered "inside"; if
  637.  *    itemPtr isn't filled, then "inside" means only the area
  638.  *    occupied by the outline.
  639.  *
  640.  * Side effects:
  641.  *    None.
  642.  *
  643.  *--------------------------------------------------------------
  644.  */
  645.  
  646.     /* ARGSUSED */
  647. static double
  648. OvalToPoint(canvasPtr, itemPtr, pointPtr)
  649.     Tk_Canvas *canvasPtr;    /* Canvas containing item. */
  650.     Tk_Item *itemPtr;        /* Item to check against point. */
  651.     double *pointPtr;        /* Pointer to x and y coordinates. */
  652. {
  653.     register RectOvalItem *ovalPtr = (RectOvalItem *) itemPtr;
  654.     double width;
  655.     int filled;
  656.  
  657.     width = ovalPtr->width;
  658.     filled = ovalPtr->fillGC != None;
  659.     if (ovalPtr->outlineGC == None) {
  660.     width = 0.0;
  661.     filled = 1;
  662.     }
  663.     return TkOvalToPoint(ovalPtr->bbox, width, filled, pointPtr);
  664. }
  665.  
  666. /*
  667.  *--------------------------------------------------------------
  668.  *
  669.  * RectToArea --
  670.  *
  671.  *    This procedure is called to determine whether an item
  672.  *    lies entirely inside, entirely outside, or overlapping
  673.  *    a given rectangle.
  674.  *
  675.  * Results:
  676.  *    -1 is returned if the item is entirely outside the area
  677.  *    given by rectPtr, 0 if it overlaps, and 1 if it is entirely
  678.  *    inside the given area.
  679.  *
  680.  * Side effects:
  681.  *    None.
  682.  *
  683.  *--------------------------------------------------------------
  684.  */
  685.  
  686.     /* ARGSUSED */
  687. static int
  688. RectToArea(canvasPtr, itemPtr, areaPtr)
  689.     Tk_Canvas *canvasPtr;    /* Canvas containing item. */
  690.     Tk_Item *itemPtr;        /* Item to check against rectangle. */
  691.     double *areaPtr;        /* Pointer to array of four coordinates
  692.                  * (x1, y1, x2, y2) describing rectangular
  693.                  * area.  */
  694. {
  695.     register RectOvalItem *rectPtr = (RectOvalItem *) itemPtr;
  696.     double halfWidth;
  697.  
  698.     halfWidth = rectPtr->width/2.0;
  699.     if (rectPtr->outlineGC == None) {
  700.     halfWidth = 0.0;
  701.     }
  702.  
  703.     if ((areaPtr[2] <= (rectPtr->bbox[0] - halfWidth))
  704.         || (areaPtr[0] >= (rectPtr->bbox[2] + halfWidth))
  705.         || (areaPtr[3] <= (rectPtr->bbox[1] - halfWidth))
  706.         || (areaPtr[1] >= (rectPtr->bbox[3] + halfWidth))) {
  707.     return -1;
  708.     }
  709.     if ((rectPtr->fillGC == None) && (rectPtr->outlineGC != None)
  710.         && (areaPtr[0] >= (rectPtr->bbox[0] + halfWidth))
  711.         && (areaPtr[1] >= (rectPtr->bbox[1] + halfWidth))
  712.         && (areaPtr[2] <= (rectPtr->bbox[2] - halfWidth))
  713.         && (areaPtr[3] <= (rectPtr->bbox[3] - halfWidth))) {
  714.     return -1;
  715.     }
  716.     if ((areaPtr[0] <= (rectPtr->bbox[0] - halfWidth))
  717.         && (areaPtr[1] <= (rectPtr->bbox[1] - halfWidth))
  718.         && (areaPtr[2] >= (rectPtr->bbox[2] + halfWidth))
  719.         && (areaPtr[3] >= (rectPtr->bbox[3] + halfWidth))) {
  720.     return 1;
  721.     }
  722.     return 0;
  723. }
  724.  
  725. /*
  726.  *--------------------------------------------------------------
  727.  *
  728.  * OvalToArea --
  729.  *
  730.  *    This procedure is called to determine whether an item
  731.  *    lies entirely inside, entirely outside, or overlapping
  732.  *    a given rectangular area.
  733.  *
  734.  * Results:
  735.  *    -1 is returned if the item is entirely outside the area
  736.  *    given by rectPtr, 0 if it overlaps, and 1 if it is entirely
  737.  *    inside the given area.
  738.  *
  739.  * Side effects:
  740.  *    None.
  741.  *
  742.  *--------------------------------------------------------------
  743.  */
  744.  
  745.     /* ARGSUSED */
  746. static int
  747. OvalToArea(canvasPtr, itemPtr, areaPtr)
  748.     Tk_Canvas *canvasPtr;    /* Canvas containing item. */
  749.     Tk_Item *itemPtr;        /* Item to check against oval. */
  750.     double *areaPtr;        /* Pointer to array of four coordinates
  751.                  * (x1, y1, x2, y2) describing rectangular
  752.                  * area.  */
  753. {
  754.     register RectOvalItem *ovalPtr = (RectOvalItem *) itemPtr;
  755.     double oval[4], halfWidth;
  756.     int result;
  757.  
  758.     /*
  759.      * Expand the oval to include the width of the outline, if any.
  760.      */
  761.  
  762.     halfWidth = ovalPtr->width/2.0;
  763.     if (ovalPtr->outlineGC == None) {
  764.     halfWidth = 0.0;
  765.     }
  766.     oval[0] = ovalPtr->bbox[0] - halfWidth;
  767.     oval[1] = ovalPtr->bbox[1] - halfWidth;
  768.     oval[2] = ovalPtr->bbox[2] + halfWidth;
  769.     oval[3] = ovalPtr->bbox[3] + halfWidth;
  770.  
  771.     result = TkOvalToArea(oval, areaPtr);
  772.  
  773.     /*
  774.      * If the rectangle appears to overlap the oval and the oval
  775.      * isn't filled, do one more check to see if perhaps all four
  776.      * of the rectangle's corners are totally inside the oval's
  777.      * unfilled center, in which case we should return "outside".
  778.      */
  779.  
  780.     if ((result == 0) && (ovalPtr->outlineGC != NULL)
  781.         && (ovalPtr->fillGC == NULL)) {
  782.     double centerX, centerY, width, height;
  783.     double xDelta1, yDelta1, xDelta2, yDelta2;
  784.  
  785.     centerX = (ovalPtr->bbox[0] + ovalPtr->bbox[2])/2.0;
  786.     centerY = (ovalPtr->bbox[1] + ovalPtr->bbox[3])/2.0;
  787.     width = (ovalPtr->bbox[2] - ovalPtr->bbox[0])/2.0 - halfWidth;
  788.     height = (ovalPtr->bbox[3] - ovalPtr->bbox[1])/2.0 - halfWidth;
  789.     xDelta1 = (areaPtr[0] - centerX)/width;
  790.     xDelta1 *= xDelta1;
  791.     yDelta1 = (areaPtr[1] - centerY)/height;
  792.     yDelta1 *= yDelta1;
  793.     xDelta2 = (areaPtr[2] - centerX)/width;
  794.     xDelta2 *= xDelta2;
  795.     yDelta2 = (areaPtr[3] - centerY)/height;
  796.     yDelta2 *= yDelta2;
  797.     if (((xDelta1 + yDelta1) < 1.0)
  798.         && ((xDelta1 + yDelta2) < 1.0)
  799.         && ((xDelta2 + yDelta1) < 1.0)
  800.         && ((xDelta2 + yDelta2) < 1.0)) {
  801.         return -1;
  802.     }
  803.     }
  804.     return result;
  805. }
  806.  
  807. /*
  808.  *--------------------------------------------------------------
  809.  *
  810.  * ScaleRectOval --
  811.  *
  812.  *    This procedure is invoked to rescale a rectangle or oval
  813.  *    item.
  814.  *
  815.  * Results:
  816.  *    None.
  817.  *
  818.  * Side effects:
  819.  *    The rectangle or oval referred to by itemPtr is rescaled
  820.  *    so that the following transformation is applied to all
  821.  *    point coordinates:
  822.  *        x' = originX + scaleX*(x-originX)
  823.  *        y' = originY + scaleY*(y-originY)
  824.  *
  825.  *--------------------------------------------------------------
  826.  */
  827.  
  828. static void
  829. ScaleRectOval(canvasPtr, itemPtr, originX, originY, scaleX, scaleY)
  830.     Tk_Canvas *canvasPtr;        /* Canvas containing rectangle. */
  831.     Tk_Item *itemPtr;            /* Rectangle to be scaled. */
  832.     double originX, originY;        /* Origin about which to scale rect. */
  833.     double scaleX;            /* Amount to scale in X direction. */
  834.     double scaleY;            /* Amount to scale in Y direction. */
  835. {
  836.     register RectOvalItem *rectOvalPtr = (RectOvalItem *) itemPtr;
  837.  
  838.     rectOvalPtr->bbox[0] = originX + scaleX*(rectOvalPtr->bbox[0] - originX);
  839.     rectOvalPtr->bbox[1] = originY + scaleY*(rectOvalPtr->bbox[1] - originY);
  840.     rectOvalPtr->bbox[2] = originX + scaleX*(rectOvalPtr->bbox[2] - originX);
  841.     rectOvalPtr->bbox[3] = originY + scaleY*(rectOvalPtr->bbox[3] - originY);
  842.     ComputeRectOvalBbox(canvasPtr, rectOvalPtr);
  843. }
  844.  
  845. /*
  846.  *--------------------------------------------------------------
  847.  *
  848.  * TranslateRectOval --
  849.  *
  850.  *    This procedure is called to move a rectangle or oval by a
  851.  *    given amount.
  852.  *
  853.  * Results:
  854.  *    None.
  855.  *
  856.  * Side effects:
  857.  *    The position of the rectangle or oval is offset by
  858.  *    (xDelta, yDelta), and the bounding box is updated in the
  859.  *    generic part of the item structure.
  860.  *
  861.  *--------------------------------------------------------------
  862.  */
  863.  
  864. static void
  865. TranslateRectOval(canvasPtr, itemPtr, deltaX, deltaY)
  866.     Tk_Canvas *canvasPtr;        /* Canvas containing item. */
  867.     Tk_Item *itemPtr;            /* Item that is being moved. */
  868.     double deltaX, deltaY;        /* Amount by which item is to be
  869.                      * moved. */
  870. {
  871.     register RectOvalItem *rectOvalPtr = (RectOvalItem *) itemPtr;
  872.  
  873.     rectOvalPtr->bbox[0] += deltaX;
  874.     rectOvalPtr->bbox[1] += deltaY;
  875.     rectOvalPtr->bbox[2] += deltaX;
  876.     rectOvalPtr->bbox[3] += deltaY;
  877.     ComputeRectOvalBbox(canvasPtr, rectOvalPtr);
  878. }
  879.